package com.insight.modules.system.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuanqiao.insight.common.constant.CommonConstant;
import com.yuanqiao.insight.common.util.common.LocalCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import com.insight.common.api.vo.Result;
import com.insight.common.aspect.annotation.AutoLog;
import com.insight.common.system.api.ISysBaseAPI;
import com.insight.common.system.query.QueryGenerator;
import com.insight.common.system.vo.LoginUser;
import com.insight.common.util.oConvertUtils;
import com.insight.modules.system.entity.SysLog;
import com.insight.modules.system.entity.SysLogPojo;
import com.insight.modules.system.service.ISysLogService;
import com.insight.modules.system.service.ISysUserRoleService;
import com.insight.modules.system.util.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 系统日志表 前端控制器
 * </p>
 *
 * @Author zhangweijian
 * @since 2018-12-26
 */
@RestController
@RequestMapping("/sys/log")
@Slf4j
public class SysLogController {

    @Autowired
    private ISysLogService sysLogService;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Autowired
    private ISysUserRoleService userRoleService;

    private static final LocalCacheUtils cacheUtils = LocalCacheUtils.getInstance();

    /**
     * 日志分页列表查询接口
     * 功能说明：
     * 1. 安全保密员可以查看普通用户和安全审计员的日志；
     * 2. 安全审计员可以查看系统管理员和安全保密员的日志。
     *
     * @param syslog    查询条件对象
     * @param pageNo    当前页码，默认1
     * @param pageSize  每页数量，默认10
     * @param req       Http请求，用于获取请求参数
     * @return          包含分页日志数据的Result对象
     */
    @AutoLog(value = "日志管理-分页列表查询")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public Result<IPage<SysLog>> queryPageList(SysLog syslog,
                                               @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                               @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                               HttpServletRequest req) {
        // 获取当前登录用户信息
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        int logType = 1;
        if (syslog.getLogType() != null && syslog.getLogType() == 2) {
            logType = 2;
            syslog.setLogType(null); // 重置避免影响查询
        }

        // 构建查询条件Wrapper
        QueryWrapper<SysLog> queryWrapper = QueryGenerator.initQueryWrapper(syslog, req.getParameterMap());

        // 只查询未被删除的日志（is_deleted字段为null）
        queryWrapper.isNull("is_deleted");

        // 针对不同日志类型过滤
        queryWrapper.in(logType == 2, "log_type", 2, 3);

        // 读取系统缓存配置，用于三员相关的特殊查询控制
        int isThreePowers = Integer.parseInt((String) cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "insight_threePowers_isEnable"));
        int logChange = Integer.parseInt(Optional.ofNullable(cacheUtils.getValueByKey(CommonConstant.DATA_DICT_KEY + "insight_threePowers_logChange")).orElse("0").toString());

        if (isThreePowers == 1) {
            // 获取当前用户的角色code列表
            List<String> roleCodes = sysBaseAPI.getRoleCodeByUsername(sysUser.getUsername());
            if (logChange == 0) {
                // 使用第一种过滤规则
                searchLog1(roleCodes, queryWrapper);
            } else {
                // 使用第二种过滤规则（深圳特供）
                searchLog2(roleCodes, queryWrapper);
            }
        }

        // 处理日志内容关键字过滤
        String keyWord = req.getParameter("keyWord");
        if (oConvertUtils.isNotEmpty(keyWord)) {
            queryWrapper.like("log_content", keyWord);
        }

        // TODO: 这里可以加更多过滤条件处理，比如时间范围过滤、字段筛选等

        Result<IPage<SysLog>> result = new Result<>();
        Page<SysLog> page = new Page<>(pageNo, pageSize);

        // 分页查询日志
        IPage<SysLog> pageList = sysLogService.page(page, queryWrapper);

        // 记录查询日志（当前页、条数、总数等）
        log.info("查询当前页：" + pageList.getCurrent());
        log.info("查询当前页数量：" + pageList.getSize());
        log.info("查询结果数量：" + pageList.getRecords().size());
        log.info("数据总数：" + pageList.getTotal());

        result.setSuccess(true);
        result.setResult(pageList);
        return result;
    }

    /**
     * 逻辑删除单条日志记录接口
     *
     * @param id 需要删除的日志ID
     * @return   操作结果，成功或失败
     */
    @RequestMapping(value = "/delete", method = RequestMethod.PUT)
    public Result<SysLog> delete(@RequestParam(name = "id", required = true) String id) {
        Result<SysLog> result = new Result<>();
        SysLog sysLog = sysLogService.getById(id);
        if (sysLog == null) {
            result.error500("未找到对应实体");
        } else {
            if (sysLog.getIsDeleted() != null) {
                result.error500("未找到对应实体!");
            }
            UpdateWrapper<SysLog> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", id);
            updateWrapper.set("is_deleted", 1);  // 标记为已删除
            boolean ok = sysLogService.update(sysLog, updateWrapper);
            if (ok) {
                result.success("删除成功!");
            }
        }
        return result;
    }

    /**
     * 批量逻辑删除日志接口
     *
     * @param ids 多个日志ID，逗号分隔
     * @return    操作结果
     */
    @RequestMapping(value = "/DeleteBatch", method = RequestMethod.PUT)
    public Result<SysLog> DeleteBatch(@RequestParam(name = "ids", required = true) String ids) {
        Result<SysLog> result = new Result<>();
        if (ids == null || "".equals(ids.trim())) {
            result.error500("参数不识别！");
        } else {
            List<String> idList = Arrays.asList(ids.split(","));
            // 批量设置is_deleted字段为1
            this.sysLogService.update(null, Wrappers.lambdaUpdate(SysLog.class)
                    .in(SysLog::getId, idList)
                    .set(SysLog::getIsDeleted, 1));
            result.success("删除成功!");
        }
        return result;
    }

    /**
     * 另一版本的分页查询接口，支持按时间范围、内容、用户名、日志类型过滤
     */
    @GetMapping(value = "/querylist")
    public Result<?> queryPageList1(SysLog sysLog,
                                    @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                    @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                    @RequestParam(required = false, name = "time1") String time1,
                                    @RequestParam(required = false, name = "time2") String time2,
                                    @RequestParam(required = false, name = "logContent") String logContent,
                                    @RequestParam(required = false, name = "username") String username,
                                    @RequestParam(required = false, name = "logType") String logType,
                                    HttpServletRequest req) {
        Page<SysLog> page = new Page<>(pageNo, pageSize);
        QueryWrapper<SysLog> queryWrapper = new QueryWrapper<>();

        // 时间区间查询
        if (StringUtils.isNotBlank(time1) && StringUtils.isNotBlank(time2)) {
            queryWrapper.between("create_time", time1, time2);
        }

        // 关键词模糊查询
        if (StringUtils.isNotBlank(logContent)) {
            queryWrapper.like("log_content", logContent);
        }

        // 精确匹配用户名
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.eq("username", username);
        }

        // 精确匹配日志类型
        if (StringUtils.isNotBlank(logType)) {
            queryWrapper.eq("log_type", logType);
        }

        // 过滤已删除日志
        queryWrapper.isNull("is_deleted");

        IPage<SysLog> pageList = sysLogService.page(page, queryWrapper);
        return Result.OK(pageList);
    }

    /**
     * 导出日志Excel接口
     * 支持多种条件过滤和选中多条记录导出，导出文件内容根据日志类型不同命名不同
     */
    @GetMapping("/exportXls")
    public void countExport(HttpServletResponse response, HttpServletRequest request,
                            @RequestParam(required = false, name = "time1") String time1,
                            @RequestParam(required = false, name = "time2") String time2,
                            @RequestParam(required = false, name = "logContent") String logContent,
                            @RequestParam(required = false, name = "username") String username,
                            @RequestParam(required = false, name = "logType") String logType,
                            @RequestParam(required = false, name = "selections") String selections) {

        QueryWrapper<SysLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("is_deleted");

        if (StringUtils.isNotEmpty(time1) && StringUtils.isNotEmpty(time2)) {
            queryWrapper.between("create_time", time1, time2);
        }
        if (StringUtils.isNotBlank(logContent)) {
            queryWrapper.like("log_content", logContent);
        }
        if (StringUtils.isNotBlank(username)) {
            queryWrapper.eq("username", username);
        }
        if (StringUtils.isNotBlank(logType)) {
            queryWrapper.eq("log_type", logType);
        }
        if (StringUtils.isNotBlank(selections)) {
            List<String> idList = Arrays.asList(selections.split(","));
            queryWrapper.in("id", idList);
        }
        queryWrapper.orderByDesc("create_time"); // 最新日志排前面

        List<SysLog> list = sysLogService.list(queryWrapper);

        // 转换为导出对象，格式化时间，转换操作类型和日志类型为中文描述
        ArrayList<SysLogPojo> sysLogPojos = new ArrayList<>();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (SysLog record : list) {
            SysLogPojo sysLogpojo = new SysLogPojo();
            sysLogpojo.setCreateTime(sdf1.format(record.getCreateTime()));
            sysLogpojo.setIp(record.getIp());
            sysLogpojo.setLogContent(record.getLogContent());

            if (record.getLogType() == 1) {
                sysLogpojo.setLogType("登录日志");
            } else if (record.getLogType() == 2) {
                sysLogpojo.setLogType("操作日志");
            }

            if (record.getOperateType() == null) {
                sysLogpojo.setOperateType("");
            } else {
                switch (record.getOperateType()) {
                    case 1 -> sysLogpojo.setOperateType("查询");
                    case 2 -> sysLogpojo.setOperateType("添加");
                    case 3 -> sysLogpojo.setOperateType("修改");
                    case 4 -> sysLogpojo.setOperateType("删除");
                    case 5 -> sysLogpojo.setOperateType("导入");
                    case 6 -> sysLogpojo.setOperateType("导出");
                    default -> sysLogpojo.setOperateType("");
                }
            }
            sysLogpojos.add(sysLogpojo);
        }

        // 根据日志类型选择导出文件名和标题
        if ("1".equals(logType)) {
            FileUtils.exportExcel(sysLogPojos, "登录日志列表", "登录日志列表", SysLogPojo.class, "登录日志列表.xls", response);
        } else if ("2".equals(logType)) {
            FileUtils.exportExcel(sysLogPojos, "操作日志列表", "操作日志列表", SysLogPojo.class, "操作日志列表.xls", response);
        } else {
            FileUtils.exportExcel(sysLogPojos, "日志列表", "日志列表", SysLogPojo.class, "日志列表.xls", response);
        }
    }

    /**
     * 三员规则过滤 - 方案1
     * @param roleCodes 当前用户角色列表
     * @param queryWrapper 查询条件Wrapper，用于动态拼接查询条件
     *
     * 逻辑：
     * - 如果当前用户是安全保密员，则只能查看安全审计员日志
     * - 如果当前用户是安全审计员，则只能查看普通用户、系统管理员和安全保密员日志
     */
    private void searchLog1(List<String> roleCodes, QueryWrapper<SysLog> queryWrapper) {
        for (String roleCode : roleCodes) {
            List<String> userNames;
            if (SysRoleController.getRoleSecadm().contains(roleCode)) {
                // 当前用户是安全保密员，查看安全审计员日志
                final List<String> roleAuditadm = SysRoleController.getRoleAuditadm();
                userNames = sysBaseAPI.getUsernameByRoleCodes(roleAuditadm);
                queryWrapper.in("userid", userNames);
                break;
            } else if (SysRoleController.getRoleAuditadm().contains(roleCode)) {
                // 当前用户是安全审计员，查看普通用户、系统管理员和安全保密员日志
                final List<String> roleRoot = SysRoleController.getRoleRoot();
                roleRoot.add("admin"); // 加入超级管理员角色
                userNames = sysBaseAPI.getUsernameByRoleCodes(roleRoot);
                queryWrapper.notIn("userid", userNames);
                break;
            }
        }
    }

    /**
     * 三员规则过滤 - 方案2（深圳特供）
     * @param roleCodes 当前用户角色列表
     * @param queryWrapper 查询条件Wrapper，用于动态拼接查询条件
     *
     * 逻辑：
     * - 安全保密员查看除admin、系统管理员和安全保密员以外用户日志
     * - 安全审计员查看系统管理员和安全保密员日志
     */
    private void searchLog2(List<String> roleCodes, QueryWrapper<SysLog> queryWrapper) {
        final List<String> roleRoot = SysRoleController.getRoleRoot();
        final List<String> roleSecadm = SysRoleController.getRoleSecadm();
        for (String roleCode : roleCodes) {
            List<String> userNames;
            final List<String> ids = new ArrayList<>();
            if (SysRoleController.getRoleSecadm().contains(roleCode)) {
                // 当前用户是安全保密员
                ids.add("admin");
                ids.addAll(roleRoot);
                ids.addAll(roleSecadm);
                userNames = sysBaseAPI.getUsernameByRoleCodes(ids);
                queryWrapper.notIn("userid", userNames);
                break;
            } else if (SysRoleController.getRoleAuditadm().contains(roleCode)) {
                // 当前用户是安全审计员
                ids.addAll(roleRoot);
                ids.addAll(roleSecadm);
                userNames = sysBaseAPI.getUsernameByRoleCodes(ids);
                queryWrapper.in("userid", userNames);
                break;
            }
        }
    }
}

